home *** CD-ROM | disk | FTP | other *** search
- /* TCP control and status routines
- * Copyright 1991 Phil Karn, KA9Q
- *
- * Mods by G1EMM
- * Mods by WG7J
- * Mods by WA3DSP
- * Mods by PA0GRI
- * Copyright 1992 Gerard J van der Grinten, PA0GRI
- */
-
- #include <stdio.h>
- #include <dos.h>
- #include "global.h"
- #include "config.h"
- #include "timer.h"
- #include "mbuf.h"
- #include "netuser.h"
- #include "internet.h"
- #include "tcp.h"
- #include "cmdparse.h"
- #include "commands.h"
-
- #ifdef TCPACCESS
- static int doaccess __ARGS((int argc,char *argv[],void *p));
- void addtaccess __ARGS((int32 target,unsigned int bits,int16 low,int16 high,int16 permit));
- #endif
- static int doirtt __ARGS((int argc,char *argv[],void *p));
- static int domss __ARGS((int argc,char *argv[],void *p));
- static int dortt __ARGS((int argc,char *argv[],void *p));
- static int dotcpkick __ARGS((int argc,char *argv[],void *p));
- static int dotcpreset __ARGS((int argc,char *argv[],void *p));
- static int dotcpretries __ARGS((int argc,char *argv[],void *p));
- static int dotcpstat __ARGS((int argc,char *argv[],void *p));
- static int dotcptimer __ARGS((int argc,char *argv[],void *p));
- static int dotcptr __ARGS((int argc,char *argv[],void *p));
- static int dowindow __ARGS((int argc,char *argv[],void *p));
- static int dosyndata __ARGS((int argc,char *argv[],void *p));
- static int doview __ARGS((int argc,char *argv[],void *p));
- static int dotcpblimit __ARGS((int argc,char *argv[],void *p));
- void rxtx_data_compute __ARGS((struct tcb *tcb,int32 *sent,int32 *recvd));
- static int tstat __ARGS((void));
- #ifdef TCPACCESS
- struct rtaccess *TCPaccess = NULLACCESS; /* access list */
- #endif
-
- /* TCP subcommand table */
- static struct cmds DFAR Tcpcmds[] = {
- #ifdef TCPACCESS
- "access", doaccess, 0, 0, NULLCHAR,
- #endif
- "blimit", dotcpblimit, 0, 0, NULLCHAR,
- "irtt", doirtt, 0, 0, NULLCHAR,
- "kick", dotcpkick, 0, 2, "tcp kick <tcb>",
- "mss", domss, 0, 0, NULLCHAR,
- "reset", dotcpreset, 0, 2, "tcp reset <tcb>",
- "retries", dotcpretries, 0,0, NULLCHAR,
- "rtt", dortt, 0, 3, "tcp rtt <tcb> <val>",
- "status", dotcpstat, 0, 0, NULLCHAR,
- "syndata", dosyndata, 0, 0, NULLCHAR,
- "timertype", dotcptimer, 0, 0, NULLCHAR,
- "trace", dotcptr, 0, 0, NULLCHAR,
- "view", doview, 0, 0, NULLCHAR,
- "window", dowindow, 0, 0, NULLCHAR,
- NULLCHAR,
- };
- int
- dotcp(argc,argv,p)
- int argc;
- char *argv[];
- void *p;
- {
- return subcmd(Tcpcmds,argc,argv,p);
- }
- static int
- dotcptr(argc,argv,p)
- int argc;
- char *argv[];
- void *p;
- {
- return setbool(&Tcp_trace,"TCP state tracing",argc,argv);
- }
-
- /* Eliminate a TCP connection */
- static int
- dotcpreset(argc,argv,p)
- int argc;
- char *argv[];
- void *p;
- {
- register struct tcb *tcb;
-
- #ifndef TNOS_68K
- tcb = MK_FP(htoi(argv[1]),8);
- #else
- tcb = htoi(argv[1]);
- #endif
- if(!tcpval(tcb)){
- tprintf(Notval);
- return 1;
- }
- reset_tcp(tcb);
- return 0;
- }
-
- /* Set initial round trip time for new connections */
- static int
- doirtt(argc,argv,p)
- int argc;
- char *argv[];
- void *p;
- {
- struct tcp_rtt *tp;
-
- setlong(&Tcp_irtt,"TCP default irtt",argc,argv);
- if(argc < 2){
- for(tp = &Tcp_rtt[0];tp < &Tcp_rtt[RTTCACHE];tp++){
- if(tp->addr != 0){
- if(tprintf("%s: srtt %lu mdev %lu\n",
- inet_ntoa(tp->addr),
- tp->srtt,tp->mdev) == EOF)
- break;
- }
- }
- }
- return 0;
- }
-
- /* Set smoothed round trip time for specified TCB */
- static int
- dortt(argc,argv,p)
- int argc;
- char *argv[];
- void *p;
- {
- register struct tcb *tcb;
- #ifndef TNOS_68K
- tcb = MK_FP(htoi(argv[1]),8);
- #else
- tcb = htoi(argv[1]);
- #endif
- if(!tcpval(tcb)){
- tprintf(Notval);
- return 1;
- }
- tcb->srtt = atol(argv[2]);
- return 0;
- }
-
- /* Force a retransmission */
- static int
- dotcpkick(argc,argv,p)
- int argc;
- char *argv[];
- void *p;
- {
- register struct tcb *tcb;
- #ifndef TNOS_68K
- tcb = MK_FP(htoi(argv[1]),8);
- #else
- tcb = htoi(argv[1]);
- #endif
- if(kick_tcp(tcb) == -1){
- tprintf(Notval);
- return 1;
- }
- return 0;
- }
-
- /* Set default maximum segment size */
- static int
- domss(argc,argv,p)
- int argc;
- char *argv[];
- void *p;
- {
- return setshort(&Tcp_mss,"TCP MSS",argc,argv);
- }
-
- /* Set default window size */
- static int
- dowindow(argc,argv,p)
- int argc;
- char *argv[];
- void *p;
- {
- return setshort(&Tcp_window,"TCP window",argc,argv);
- }
-
- static int
- dosyndata(argc,argv,p)
- int argc;
- char *argv[];
- void *p;
- {
- return setbool(&Tcp_syndata,"TCP syn+data piggybacking",argc,argv);
- }
-
- extern int Tcp_retries;
-
- /* Set maximum number of backoffs before resetting the connection */
- static int
- dotcpretries(argc,argv,p)
- int argc;
- char *argv[];
- void *p;
- {
- return setint(&Tcp_retries,"max. retries",argc,argv);
- }
-
- extern int Tcp_blimit;
-
- /* Set backoff limit on the connection; from N1BEE */
- static int
- dotcpblimit(argc,argv,p)
- int argc;
- char *argv[];
- void *p;
- {
- return setint(&Tcp_blimit,"backoff limit",argc,argv);
- }
-
- /* Display status of TCBs */
- static int
- dotcpstat(argc,argv,p)
- int argc;
- char *argv[];
- void *p;
- {
- register struct tcb *tcb;
-
- if(argc < 2){
- tstat();
- } else {
-
- #ifndef TNOS_68K
- tcb = MK_FP(htoi(argv[1]),8);
- #else
- tcb = htoi(argv[1]);
- #endif
- if(!tcpval(tcb))
- tprintf(Notval);
- else
- st_tcp(tcb);
- }
- return 0;
- }
-
- /* Dump TCP stats and summary of all TCBs
- /* &TCB Rcv-Q Snd-Q Local socket Remote socket State
- * 1234 0 0 xxx.xxx.xxx.xxx:xxxxx xxx.xxx.xxx.xxx:xxxxx Established
- * Dump display for TNOS_68K
- * &TCB Rcv-Q Snd-Q Local socket Remote socket State
- * 123456 0 0 xxx.xxx.xxx.xxx:xxxxx xxx.xxx.xxx.xxx:xxxxx Established
- */
- static int
- tstat()
- {
- register int i;
- register struct tcb *tcb;
- int j;
-
- for(j=i=1;i<=NUMTCPMIB;i++){
- if(Tcp_mib[i].name == NULLCHAR)
- continue;
- tprintf("(%2u)%-20s%10lu",i,Tcp_mib[i].name,
- Tcp_mib[i].value.integer);
- if(j++ % 2)
- tprintf(" ");
- else
- tprintf("\n");
- }
- if((j % 2) == 0)
- tprintf("\n");
-
- #ifndef TNOS_68K
- tprintf("&TCB Rcv-Q Snd-Q Local socket Remote socket State\n");
- #else
- tprintf("&TCB Rcv-Q Snd-Q Local socket Remote socket State\n");
- #endif
- for(tcb=Tcbs;tcb != NULLTCB;tcb = tcb->next){
- #ifndef TNOS_68K
- tprintf("%4.4x%6u%6u ",
- #else
- tprintf("%-8.8x%6u%6u ",
- #endif
- FP_SEG(tcb),tcb->rcvcnt,tcb->sndcnt);
- tprintf("%-23s",pinet(&tcb->conn.local));
- tprintf("%-23s",pinet(&tcb->conn.remote));
- tprintf("%-s",Tcpstates[tcb->state]);
- if(tcb->state == TCP_LISTEN && tcb->flags.clone)
- tprintf(" (S)");
- if(tprintf("\n") == EOF)
- return 0;
- }
- return 0;
- }
- /* Dump a TCP control block in detail */
- void
- st_tcp(tcb)
- struct tcb *tcb;
- {
- int32 sent,recvd;
-
- if(tcb == NULLTCB)
- return;
-
- rxtx_data_compute(tcb,&sent,&recvd);
-
- tprintf("Local: %s",pinet(&tcb->conn.local));
- tprintf(" Remote: %s",pinet(&tcb->conn.remote));
- tprintf(" State: %s\n",Tcpstates[tcb->state]);
- tprintf(" Init seq Unack Next Resent CWind Thrsh Wind MSS Queue Total\n");
- tprintf("Send:");
- tprintf("%9lx",tcb->iss);
- tprintf("%9lx",tcb->snd.una);
- tprintf("%9lx",tcb->snd.nxt);
- tprintf("%7lu",tcb->resent);
- tprintf("%6u",tcb->cwind);
- tprintf("%6u",tcb->ssthresh);
- tprintf("%6u",tcb->snd.wnd);
- tprintf("%5u",tcb->mss);
- tprintf("%6u",tcb->sndcnt);
- tprintf("%11lu\n",sent);
-
- tprintf("Recv:");
- tprintf("%9lx",tcb->irs);
- tprintf(" ");
- tprintf("%9lx",tcb->rcv.nxt);
- tprintf("%7lu",tcb->rerecv);
- tprintf(" ");
- tprintf(" ");
- tprintf("%6u",tcb->rcv.wnd);
- tprintf(" ");
- tprintf("%6u",tcb->rcvcnt);
- tprintf("%11lu\n",recvd);
-
- if(tcb->reseq != (struct reseq *)NULL){
- register struct reseq *rp;
-
- tprintf("Reassembly queue:\n");
- for(rp = tcb->reseq;rp != (struct reseq *)NULL; rp = rp->next){
- if(tprintf(" seq x%lx %u bytes\n",
- rp->seg.seq,rp->length) == EOF)
- return;
- }
- }
- if(tcb->backoff > 0)
- tprintf("Backoff %u ",tcb->backoff);
- if(tcb->flags.retran)
- tprintf("Retrying ");
- switch(tcb->timer.state){
- case TIMER_STOP:
- tprintf("Timer stopped ");
- break;
- case TIMER_RUN:
- tprintf("Timer running (%ld/%ld ms) ",
- (long)read_timer(&tcb->timer),
- (long)dur_timer(&tcb->timer));
- break;
- case TIMER_EXPIRE:
- tprintf("Timer expired ");
- }
- tprintf("SRTT %ld ms Mean dev %ld ms\n",tcb->srtt,tcb->mdev);
- }
-
- void
- rxtx_data_compute(tcb,sent,recvd)
- struct tcb *tcb;
- int32 *sent;
- int32 *recvd;
- {
-
- /* Compute total data sent and received; take out SYN and FIN */
- *sent = tcb->snd.una - tcb->iss; /* Acknowledged data only */
- *recvd = tcb->rcv.nxt - tcb->irs;
- switch(tcb->state){
- case TCP_LISTEN:
- case TCP_SYN_SENT: /* Nothing received or acked yet */
- *sent = *recvd = 0;
- break;
- case TCP_SYN_RECEIVED:
- (*recvd)--; /* Got SYN, no data acked yet */
- *sent = 0;
- break;
- case TCP_ESTABLISHED: /* Got and sent SYN */
- case TCP_FINWAIT1: /* FIN not acked yet */
- (*sent)--;
- (*recvd)--;
- break;
- case TCP_FINWAIT2: /* Our SYN and FIN both acked */
- *sent -= 2;
- (*recvd)--;
- break;
- case TCP_CLOSE_WAIT: /* Got SYN and FIN, our FIN not yet acked */
- case TCP_CLOSING:
- case TCP_LAST_ACK:
- (*sent)--;
- *recvd -= 2;
- break;
- case TCP_TIME_WAIT: /* Sent and received SYN/FIN, all acked */
- *sent -= 2;
- *recvd -= 2;
- break;
- }
- }
-
- /* TCP View Command - D. Crompton 1/92 */
- /* Modified for sorted display and */
- /* two views - tcp view b|t - 3/92 */
-
- static int
- doview(argc,argv,p)
- int argc;
- char *argv[];
- void *p;
-
- {
- register struct tcb *tcb;
- int32 sent,recvd;
- int i,j,k=0,vtype;
- char temp[40];
- char *buf;
-
- if(argc == 1)
- vtype = 1;
- else {
- switch (argv[1][0]) {
- case 'b': vtype=1;
- break;
- case 't': vtype=0;
- break;
- default: tprintf("Use: tcp view <bytes|timers>\n");
- return 0;
- }
- }
-
- for(tcb=Tcbs,i=0;tcb != NULLTCB;tcb = tcb->next){
- if(tcb->state == TCP_LISTEN)
- continue;
- i++;
- }
-
- if (i) {
- buf=mallocw(i*80);
-
- if (vtype) {
- tprintf(" Send Send Receive Receive\n");
- tprintf("Remote Socket:Port:Local Port/State &TCB Bytes Retries Bytes Retries\n");
- } else {
- tprintf("Remote Socket:Port:Local Port/State &TCB Boff State Timer SRTT\n");
- }
- for(tcb=Tcbs,j=0;tcb != NULLTCB;tcb = tcb->next){
- if(tcb->state == TCP_LISTEN)
- continue;
-
- strcpy(temp,pinet(&tcb->conn.remote));
- strcat(temp,strstr(pinet(&tcb->conn.local),":"));
- strcat(temp,"/");
- strcat(temp,Tcpstates[tcb->state]);
- temp[37]=0;
- k=sprintf(&buf[j],"%-37s",temp);
- sprintf(temp,"%8lx",ptol(tcb));
- temp[4]=0;
- k+=sprintf(&buf[j+k]," %4s",temp);
- if (vtype) {
- rxtx_data_compute(tcb,&sent,&recvd);
- k+=sprintf(&buf[j+k],"%10lu ",sent);
- k+=sprintf(&buf[j+k],"%7lu ",tcb->resent);
- k+=sprintf(&buf[j+k],"%10lu ",recvd);
- sprintf(&buf[j+k],"%7lu",tcb->rerecv);
- } else {
- k+=sprintf(&buf[j+k]," %4u",tcb->backoff);
- if(tcb->flags.retran)
- k+=sprintf(&buf[j+k]," Retry ");
- else
- k+=sprintf(&buf[j+k]," Try ");
- switch(tcb->timer.state) {
- case TIMER_STOP:
- k+=sprintf(&buf[j+k]," Stopped");
- break;
- case TIMER_RUN:
- k+=sprintf(&buf[j+k]," Run (");
- if ((long)dur_timer(&tcb->timer)<10000) {
- k+=sprintf(&buf[j+k],"%ld/%ld)ms",
- (long)read_timer(&tcb->timer),
- (long)dur_timer(&tcb->timer));
- } else {
- if (((long)read_timer(&tcb->timer)/1000)>9999) {
- k+=sprintf(&buf[j+k],">9999/9999)s");
- } else {
- k+=sprintf(&buf[j+k],"%ld/%ld)s",
- (long)read_timer(&tcb->timer)/1000,
- (long)dur_timer(&tcb->timer)/1000);
- }
- }
- break;
- case TIMER_EXPIRE:
- k+=sprintf(&buf[j+k]," Expired");
- }
- for (;k<73;k++)
- buf[j+k]=' ';
- if ((tcb->srtt)<10000) {
- sprintf(&buf[j+73],"%4ldms",tcb->srtt);
- } else {
- if ((tcb->srtt/1000)>9999) {
- sprintf(&buf[j+73],">9999s");
- } else {
- sprintf(&buf[j+73],"%4lds",tcb->srtt/1000);
- }
- }
- }
- j+=80;
- }
-
- qsort(buf,(size_t)i,80,strcmp);
-
- for (j=0,k=0;j<i;j++,k+=80) {
- tprintf("%s",&buf[k]);
- if(tprintf("\n") == EOF)
- return 0;
- }
- free(buf);
- }
- return 0;
- }
-
- /* tcp timers type - linear v exponential */
- static
- dotcptimer(argc,argv,p)
- int argc ;
- char *argv[] ;
- void *p ;
- {
- extern int tcptimertype;
-
- if (argc < 2) {
- tprintf("Tcp timer type is %s\n", tcptimertype ? "linear" : "exponential" ) ;
- return 0 ;
- }
-
- switch (argv[1][0]) {
- case 'l':
- case 'L':
- tcptimertype = 1 ;
- break ;
- case 'e':
- case 'E':
- tcptimertype = 0 ;
- break ;
- default:
- tprintf("use: tcp timertype [linear|exponential]\n") ;
- return -1 ;
- }
-
- return 0 ;
- }
- #ifdef TCPACCESS
- static int
- doaccess(argc,argv,p)
- int argc;
- char *argv[];
- void *p;
- {
- struct iface *ifp;
- int32 target;
- unsigned bits;
- char *bitp;
- int16 lport,hport,state;
- char *cp; /* for printing the table */
- struct rtaccess *tpacc;
- struct rtaccess *head;
- struct rtaccess *prev;
-
- if(argc == 1){ /* print out the table */
- tprintf("IP Address Mask Low Port High Port State\n");
- for(tpacc = TCPaccess;tpacc != NULLACCESS;tpacc = tpacc->nxtbits){
- if(tpacc->target != 0)
- cp = inet_ntoa(tpacc->target);
- else
- cp = "all";
- tprintf("%-16s",cp);
- tprintf("%4u ",tpacc->bits);
- tprintf("%9u",tpacc->lowport);
- tprintf("%10u ",tpacc->highport);
- if(tpacc->status)
- cp = "deny";
- else
- cp = "permit";
- tprintf("%-6s\n",cp);
- }
- return 0;
- }
-
- if(strcmp(argv[1],"permit") == 0){
- state = 0;
- } else {
- if((strcmp(argv[1],"deny") == 0)
- || (strcmp(argv[1],"delete") == 0)){
- state = -1;
- } else {
- tprintf(" Format: tcp access <permit|deny|delete> <dest addr>[/<bits>] [lowport [highport]]\n");
- return 1;
- }
- }
- if(strcmp(argv[2],"all") == 0){
- target = 0;
- bits = 0;
- } else {
- /* If IP address is followed by an optional slash and
- * a length field, (e.g., 128.96/16) get it;
- * otherwise assume a full 32-bit address
- */
- if((bitp = strchr(argv[2],'/')) != NULLCHAR){
- /* Terminate address token for resolve() call */
- *bitp++ = '\0';
- bits = atoi(bitp);
- } else
- bits = 32;
-
- if((target = resolve(argv[2])) == 0){
- tprintf(Badhost,argv[2]);
- return 1;
- }
- }
-
- if(argc > 3){
- if(strcmp(argv[3],"all") == 0){
- lport = 1;
- hport = 65534;
- } else {
- lport = atoi(argv[3]);
- hport = lport;
- }
- } else {
- lport = 0;
- hport = 0;
- }
- if(argc > 4)
- hport = atoi(argv[4]);
-
- if(strcmp(argv[1],"delete") == 0){
- prev = NULLACCESS;
- head = tpacc = TCPaccess;
- while(tpacc != NULLACCESS){
- head = tpacc;
- tpacc = tpacc->nxtbits;
- if((head->target == target) &&
- (head->bits == bits) &&
- (head->lowport == lport) &&
- (head->highport == hport)) { /*match*/
-
-
- /*now delete. watch for special cases*/
- if(head == TCPaccess) /* first in chain */
- TCPaccess = head->nxtbits;
- else
- /*
- sanity check: we cant get here with
- prev == NULLACCESS !!
- */
- prev->nxtbits = tpacc;
- free(head);
- return 0;
- }
- prev = head;
- }
- tprintf("Not found.\n");
- return 1;
- }
- /* add the access */
- addtaccess(target,bits,lport,hport,state);
- return 0;
- }
- /* add an entry to the access control list */
- /* not a lot of error checking 8-) */
- void
- addtaccess(target,bits,low,high,permit)
- int32 target; /* Target IP address prefix */
- unsigned int bits; /* Size of target address prefix in bits (0-32) */
- int16 low;
- int16 high;
- int16 permit;
- {
- struct rtaccess *tpacc; /*temporary*/
- struct rtaccess *holder; /*for the new record*/
-
- holder = (struct rtaccess *)callocw(1,sizeof(struct rtaccess));
- holder->nxtiface = NULLACCESS;
- holder->nxtbits = NULLACCESS;
- holder->target = target;
- holder->bits = bits;
- holder->lowport = low;
- holder->highport = high;
- holder->status = permit;
- if((tpacc = TCPaccess) == NULLACCESS){
- TCPaccess = holder;
- } else {
- while(tpacc->nxtbits != NULLACCESS)
- tpacc = tpacc->nxtbits;
- tpacc->nxtbits = holder;
- }
- }
- /* check to see if port is "authorized". Returns 0 if matching permit record
- is found or no access records exists, -1 if not found or deny record found */
- int
- tcp_check(accptr,src,port)
- struct rtaccess *accptr;
- int32 src;
- int16 port;
- {
- unsigned long mask;
-
- if(accptr == NULLACCESS)
- return 0; /* no access control */
- for(;accptr != NULLACCESS;accptr = accptr->nxtbits) {
- mask = ~0L << (32 - accptr->bits);
- if(( accptr->target == (mask & src)) &&
- ((( port >= accptr->lowport ) && (port <= accptr->highport))
- || (!accptr->lowport))){
- return (accptr->status);
- }
- }
- return -1; /* fall through to here if not found */
- }
- #endif
-
-